package com.partsoft.webs.zks;

import java.util.Map;
import java.util.Map.Entry;

import org.springframework.util.Assert;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.DataBinder;

public abstract class AnnotateDataBinderComposer<T extends Component> extends GenericForwardComposer<T> {

	private static final long serialVersionUID = 5839133240210591410L;
	
	public static final String DATABINDER_ARG = "databinder";
	
	public static final String CONTROLLER_ARG = "controller";

	private boolean alreadyComposer = false;
	
	private void initAnnotateDataBinder(Component comp) {
		DataBinder dataBinder =  newDataBinder(comp);
		comp.setAttribute(DATABINDER_ARG, dataBinder, Component.COMPONENT_SCOPE);
		comp.setAttribute(CONTROLLER_ARG, this, Component.COMPONENT_SCOPE);
		Map<String, ?> bindBeans = getVariableBindBeans();
		if (bindBeans != null) {
			for (Entry<String, ?> beanEntry : bindBeans.entrySet()) {
				comp.setAttribute(beanEntry.getKey(), beanEntry.getValue(), Component.COMPONENT_SCOPE);
			}
		}
	}
	
	/**
	 * 获取用于界面绑定的变量。<br/>
	 * 如界面使用value="@{beanName}"的语法，则beanName对应一个实际的JAVA实体。
	 * @return 名称名与实际JAVA实体映射表。
	 */
	public abstract Map<String, ?> getVariableBindBeans();
	
	public DataBinder getDataBinder() {
		DataBinder dataBinder = (DataBinder) self.getAttribute(DATABINDER_ARG, Component.COMPONENT_SCOPE);
		Assert.notNull(dataBinder, "数据绑定器未初始化");
		return dataBinder;
	}
	
	/**
	 * 创建数据绑定实例（默认采用{@link AnnotateDataBinder}实现）
	 * @param comp 数据绑定根组件
	 * @return 数据绑定对象
	 */
	protected DataBinder newDataBinder(Component rootComp) {
		return new AnnotateDataBinder(rootComp);
	}

	/**
	 * 是否已经组合了组建
	 */
	public boolean hasAlreadyCompose() {
		return alreadyComposer;
	}
	
	protected void assertAlreadyCompose() {
		Assert.isTrue(hasAlreadyCompose(), "组件初始化组合尚未完成");
	}
	
	@Override
	public void doAfterCompose(T comp) throws Exception {
		this.alreadyComposer = false;
		initAnnotateDataBinder(comp);
		super.doAfterCompose(comp);
		getDataBinder().loadAll();
		this.alreadyComposer = true;
	}
	
}
